#include "viml/instruction.h"
#include "viml/value.h"
#include "viml/debug_info.h"  // 优化项1: 添加DebugInfo头文件
#include <sstream>
#include <iomanip>
#include <iostream>

namespace viml {

const char* get_opcode_name(OpCode op) {
    switch (op) {
        case OpCode::LOAD_CONST: return "LOAD_CONST";
        case OpCode::LOAD_NIL: return "LOAD_NIL";
        case OpCode::LOAD_TRUE: return "LOAD_TRUE";
        case OpCode::LOAD_FALSE: return "LOAD_FALSE";
        case OpCode::MOVE: return "MOVE";
        
        case OpCode::LOAD_GLOBAL: return "LOAD_GLOBAL";
        case OpCode::STORE_GLOBAL: return "STORE_GLOBAL";
        case OpCode::LOAD_LOCAL: return "LOAD_LOCAL";
        case OpCode::STORE_LOCAL: return "STORE_LOCAL";
        case OpCode::LOAD_SCOPE: return "LOAD_SCOPE";
        case OpCode::STORE_SCOPE: return "STORE_SCOPE";
        
        case OpCode::ADD: return "ADD";
        case OpCode::SUB: return "SUB";
        case OpCode::MUL: return "MUL";
        case OpCode::DIV: return "DIV";
        case OpCode::MOD: return "MOD";
        case OpCode::NEG: return "NEG";
        
        case OpCode::EQ: return "EQ";
        case OpCode::NE: return "NE";
        case OpCode::LT: return "LT";
        case OpCode::LE: return "LE";
        case OpCode::GT: return "GT";
        case OpCode::GE: return "GE";
        case OpCode::AND: return "AND";
        case OpCode::OR: return "OR";
        case OpCode::NOT: return "NOT";
        
        case OpCode::JMP: return "JMP";
        case OpCode::JMP_IF_TRUE: return "JMP_IF_TRUE";
        case OpCode::JMP_IF_FALSE: return "JMP_IF_FALSE";
        
        case OpCode::ITER_INIT: return "ITER_INIT";
        case OpCode::ITER_NEXT: return "ITER_NEXT";
        
        case OpCode::CALL: return "CALL";
        case OpCode::RETURN_OP: return "RETURN";
        case OpCode::FUNC_DEF: return "FUNC_DEF";
        
        case OpCode::NEW_LIST: return "NEW_LIST";
        case OpCode::NEW_DICT: return "NEW_DICT";
        case OpCode::GET_INDEX: return "GET_INDEX";
        case OpCode::SET_INDEX: return "SET_INDEX";
        case OpCode::LEN: return "LEN";
        case OpCode::LIST_APPEND: return "LIST_APPEND";
        case OpCode::DICT_SET: return "DICT_SET";
        
        case OpCode::STR_CAT: return "STR_CAT";
        
        case OpCode::BREAKPOINT: return "BREAKPOINT";
        case OpCode::DBG_LINE: return "DBG_LINE";
        
        case OpCode::ECHO: return "ECHO";
        
        case OpCode::HALT: return "HALT";
        
        default: return "UNKNOWN";
    }
}

// Instruction方法实现
std::string Instruction::to_string() const {
    std::ostringstream oss;
    OpCode op = opcode();
    const char* name = get_opcode_name(op);
    
    oss << name;
    
    switch (op) {
        // ABx格式指令
        case OpCode::LOAD_CONST:
        case OpCode::LOAD_GLOBAL:
        case OpCode::STORE_GLOBAL:
        case OpCode::LOAD_SCOPE:
        case OpCode::STORE_SCOPE:
        case OpCode::JMP_IF_TRUE:
        case OpCode::JMP_IF_FALSE:
        case OpCode::ITER_NEXT:
        case OpCode::FUNC_DEF:
        case OpCode::DBG_LINE:
            oss << " R" << static_cast<int>(a()) << ", " << bx();
            break;
            
        // Bx格式指令（仅偏移量）
        case OpCode::JMP:
            oss << " " << bx();
            break;
            
        // A格式指令
        case OpCode::LOAD_NIL:
        case OpCode::LOAD_TRUE:
        case OpCode::LOAD_FALSE:
            oss << " R" << static_cast<int>(a());
            break;
            
        // AB格式指令（寄存器-寄存器）
        case OpCode::MOVE:
        case OpCode::LOAD_LOCAL:
        case OpCode::STORE_LOCAL:
        case OpCode::NEG:
        case OpCode::NOT:
        case OpCode::NEW_LIST:
        case OpCode::LEN:
        case OpCode::LIST_APPEND:
        case OpCode::ITER_INIT:
        case OpCode::RETURN_OP:
            oss << " R" << static_cast<int>(a()) << ", R" << static_cast<int>(b());
            break;
            
        // AB格式指令（寄存器-立即数）
        case OpCode::ECHO:
            oss << " R" << static_cast<int>(a()) << ", " << static_cast<int>(b());
            break;
            
        // ABC格式指令
        case OpCode::ADD:
        case OpCode::SUB:
        case OpCode::MUL:
        case OpCode::DIV:
        case OpCode::MOD:
        case OpCode::EQ:
        case OpCode::NE:
        case OpCode::LT:
        case OpCode::LE:
        case OpCode::GT:
        case OpCode::GE:
        case OpCode::AND:
        case OpCode::OR:
        case OpCode::GET_INDEX:
        case OpCode::SET_INDEX:
        case OpCode::DICT_SET:
        case OpCode::STR_CAT:
            oss << " R" << static_cast<int>(a()) << ", R" << static_cast<int>(b()) << ", R" << static_cast<int>(c());
            break;
            
        // 特殊格式指令
        case OpCode::CALL:
            oss << " R" << static_cast<int>(a()) << ", R" << static_cast<int>(b()) << ", " << static_cast<int>(c());
            break;
            
        case OpCode::NEW_DICT:
            oss << " R" << static_cast<int>(a());
            break;
            
        case OpCode::BREAKPOINT:
        case OpCode::HALT:
            // 无操作数
            break;
            
        default:
            oss << " (unknown format)";
            break;
    }
    
    return oss.str();
}

std::string Instruction::debug_string() const {
    std::ostringstream oss;
    oss << "Instruction{raw=0x" << std::hex << std::setw(8) << std::setfill('0') << data
        << ", op=" << get_opcode_name(opcode())
        << ", a=" << std::dec << static_cast<int>(a())
        << ", b=" << static_cast<int>(b())
        << ", c=" << static_cast<int>(c())
        << ", bx=" << bx()
        << ", sbx=" << sbx() << "}";
    return oss.str();
}

// Bytecode方法实现
void Bytecode::add_instruction(const Instruction& inst) {
#ifdef DEBUG_BUILD
    std::cout << "Adding instruction to bytecode: OpCode=" << static_cast<int>(inst.opcode()) 
              << ", A=" << static_cast<int>(inst.a()) 
              << ", B=" << static_cast<int>(inst.b()) 
              << ", C=" << static_cast<int>(inst.c()) << std::endl;
#endif
    instructions.push_back(inst);
    line_numbers.push_back(line_numbers.empty() ? 1 : line_numbers.back());
}

void Bytecode::add_instruction(OpCode op, uint8_t a, uint8_t b, uint8_t c) {
    add_instruction(Instruction(op, a, b, c));
}

void Bytecode::add_instruction(OpCode op, uint8_t a, uint16_t bx) {
    add_instruction(Instruction(op, a, bx));
}

const Instruction& Bytecode::get_instruction(size_t index) const {
    if (index >= instructions.size()) {
        throw std::out_of_range("Instruction index out of range");
    }
#ifdef DEBUG_BUILD
    std::cout << "Getting instruction at index " << index 
              << ": OpCode=" << static_cast<int>(instructions[index].opcode()) 
              << ", A=" << static_cast<int>(instructions[index].a()) 
              << ", B=" << static_cast<int>(instructions[index].b()) 
              << ", C=" << static_cast<int>(instructions[index].c()) << std::endl;
#endif
    return instructions[index];
}

void Bytecode::set_instruction(size_t index, const Instruction& inst) {
    if (index >= instructions.size()) {
        throw std::out_of_range("Instruction index out of range");
    }
    instructions[index] = inst;
}

// Bytecode常量池方法实现
size_t Bytecode::add_constant(const Value& value) {
    // 检查是否已存在相同常量
    for (size_t i = 0; i < constants.size(); ++i) {
        if (constants[i] == value) {
            return i;
        }
    }
    
    constants.push_back(value);
    return constants.size() - 1;
}

const Value& Bytecode::get_constant(size_t index) const {
    if (index >= constants.size()) {
        throw std::out_of_range("Constant index out of range");
    }
    return constants[index];
}

size_t Bytecode::constant_count() const {
    return constants.size();
}

size_t Bytecode::add_name(const std::string& name) {
    // 检查是否已存在相同名字
    for (size_t i = 0; i < names.size(); ++i) {
        if (names[i] == name) {
            return i;
        }
    }
    
    names.push_back(name);
    return names.size() - 1;
}

const std::string& Bytecode::get_name(size_t index) const {
    if (index >= names.size()) {
        throw std::out_of_range("Name index out of range");
    }
    return names[index];
}

void Bytecode::add_line_number(int line) {
    if (!line_numbers.empty()) {
        line_numbers.back() = line;
    } else {
        line_numbers.push_back(line);
    }
}

int Bytecode::get_line_number(size_t pc) const {
    if (pc >= line_numbers.size()) {
        return line_numbers.empty() ? 1 : line_numbers.back();
    }
    return line_numbers[pc];
}

std::string Bytecode::disassemble() const {
    std::ostringstream oss;
    
    oss << "=== Bytecode Disassembly ===\n";
    oss << "Source: " << source_file << "\n";
    oss << "Instructions: " << instructions.size() << "\n";
    oss << "Constants: " << constants.size() << "\n";
    oss << "Names: " << names.size() << "\n\n";
    
    // 常量池
    if (!constants.empty()) {
        oss << "Constants:\n";
        for (size_t i = 0; i < constants.size(); ++i) {
            oss << "  K[" << i << "] = " << constants[i].debug_string() << "\n";
        }
        oss << "\n";
    }
    
    // 名字池
    if (!names.empty()) {
        oss << "Names:\n";
        for (size_t i = 0; i < names.size(); ++i) {
            oss << "  N[" << i << "] = \"" << names[i] << "\"\n";
        }
        oss << "\n";
    }
    
    // 指令序列
    oss << "Instructions:\n";
    for (size_t i = 0; i < instructions.size(); ++i) {
        int line = get_line_number(i);
        oss << std::setw(4) << std::setfill(' ') << i << ": ";
        oss << std::setw(4) << line << " ";
        oss << instructions[i].to_string() << "\n";
    }
    
    return oss.str();
}

void Bytecode::dump() const {
    std::cout << disassemble();
}

void Bytecode::clear() {
    instructions.clear();
    constants.clear();
    names.clear();
    line_numbers.clear();
    source_file.clear();
    debug_info_.reset();  // 优化项1: 清理调试信息
}

// 优化项1: 自动创建并初始化调试信息
std::shared_ptr<DebugInfo> Bytecode::ensure_debug_info() {
    if (!debug_info_) {
        debug_info_ = std::make_shared<DebugInfo>(source_file);
        
        // 自动同步行号映射
        for (size_t pc = 0; pc < instructions.size(); ++pc) {
            int line = get_line_number(pc);
            if (line > 0) {
                debug_info_->add_line_mapping(line, pc);
            }
        }
    }
    return debug_info_;
}

} // namespace viml